package com.commsen.sample.portlet.chatrooms.client;
import java.util.Date;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
public class Chatroom implements ValueChangeHandler<String> {
public static final String STATE_DELIMITER = ":";
public static final String STATE_INIT = "INIT";
public static final String STATE_JOINED_GROUP = "GROUP";
private ChatroomJsObject portletInstance = null;
private String currentRoom = null;
private long lastMessageTime = 0;
private final TextBox roomNameBox = new TextBox();
private final Button enterTheRoomButton = new Button("enter the room");
private final Button leaveTheRoomButton = new Button("leave the room");
private final VerticalPanel messageArea = new VerticalPanel();
private final TextBox messageBox = new TextBox();
private final Button sendMessageButton = new Button("send");
private Timer messageUpdater;
private boolean updateInProgress = false;
private RequestBuilder requestBuilder = null;
public Chatroom(ChatroomJsObject portletInstance) {
/*
* Remember the portlet instance
*/
this.portletInstance = portletInstance;
/*
* Prepare RequestBuilder
*/
requestBuilder = new RequestBuilder(RequestBuilder.POST, portletInstance.getResourceURL());
/*
* Prepare GUI
*/
drawGUI();
prepareHandlers();
History.addValueChangeHandler(this);
String state = portletInstance.getState();
if (state == null || state.isEmpty()) state = STATE_INIT;
handleState(state);
/*
* Configure the timer to retrieve messages every second
*/
messageUpdater = new Timer() {
@Override
public void run() {
if (currentRoom != null && !updateInProgress) {
getMessages();
}
}
};
messageUpdater.scheduleRepeating(1000);
}
/**
* Draws all GUI components
*/
private void drawGUI () {
FlowPanel roomSelectionPanel = new FlowPanel();
roomSelectionPanel.add(roomNameBox);
roomSelectionPanel.add(enterTheRoomButton);
roomSelectionPanel.add(leaveTheRoomButton);
FlowPanel messagePanel = new FlowPanel();
messagePanel.add(messageBox);
messagePanel.add(sendMessageButton);
ScrollPanel messageAreaScrollPanel = new ScrollPanel(messageArea);
messageAreaScrollPanel.setHeight("200px");
VerticalPanel mainPanel = new VerticalPanel();
mainPanel.add(roomSelectionPanel);
mainPanel.add(messageAreaScrollPanel);
mainPanel.add(messagePanel);
RootPanel.get("chatrooms-portlet-" + portletInstance.getId()).add(mainPanel);
}
/**
* Prepare all event handlers
*/
private void prepareHandlers() {
roomNameBox.addKeyPressHandler(new KeyPressHandler() {
@Override
public void onKeyPress(KeyPressEvent keyPressEvent) {
if (roomNameBox.getValue().trim().isEmpty()) {
enterTheRoomButton.setEnabled(false);
} else {
enterTheRoomButton.setEnabled(true);
}
}
});
enterTheRoomButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent clickEvent) {
String room = roomNameBox.getValue();
displayChatroomState(room);
saveState(STATE_JOINED_GROUP + STATE_DELIMITER + room);
}
});
leaveTheRoomButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent clickEvent) {
displayInitialState();
saveState(STATE_INIT);
}
});
sendMessageButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent clickEvent) {
sendMessageToServer(messageBox.getValue());
messageBox.setValue(null);
}
});
}
/**
* Set the properties of GUI components when user enters chatroom
*/
private void displayChatroomState (String room) {
currentRoom = room;
leaveTheRoomButton.setEnabled(true);
enterTheRoomButton.setEnabled(false);
roomNameBox.setEnabled(false);
roomNameBox.setText(room);
messageBox.setEnabled(true);
sendMessageButton.setEnabled(true);
}
/**
* Set the properties of GUI components to their initial state.
*/
private void displayInitialState () {
if (currentRoom == null) {
enterTheRoomButton.setEnabled(false);
leaveTheRoomButton.setEnabled(true);
} else {
enterTheRoomButton.setEnabled(true);
leaveTheRoomButton.setEnabled(false);
}
roomNameBox.setText(currentRoom);
roomNameBox.setEnabled(true);
currentRoom = null;
messageArea.clear();
lastMessageTime = 0;
messageBox.setEnabled(false);
sendMessageButton.setEnabled(false);
}
private void sendMessageToServer (String message) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("action", new JSONString("saveMessage"));
jsonObject.put("currentRoom", new JSONString(currentRoom));
jsonObject.put("message", new JSONString(message));
try {
requestBuilder.sendRequest(jsonObject.toString(), new RequestCallback() {
@Override
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
// do nothing
} else {
Window.alert("Error with JSON communication! Got response: " + response.getStatusCode() + " "
+ response.getStatusText());
}
}
@Override
public void onError(Request request, Throwable throwable) {
Window.alert("Error: " + throwable.getMessage());
}
});
} catch (RequestException e) {
Window.alert("Error: " + e.getMessage());
}
}
private void getMessages() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("action", new JSONString("getMessages"));
jsonObject.put("currentRoom", new JSONString(currentRoom));
jsonObject.put("lastMessageTime", new JSONNumber(lastMessageTime));
try {
requestBuilder.sendRequest(jsonObject.toString(), new RequestCallback() {
@Override
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
JsArray<ChatroomMessageJsObject> messages = json2ChatroomMessages(response.getText());
updateInProgress = true;
if (messages != null) {
for (int i = 0; i < messages.length(); i++) {
ChatroomMessageJsObject message = messages.get(i);
messageArea.add(new MessagePanel(message));
lastMessageTime = (long)message.getTime();
}
}
updateInProgress = false;
} else {
Window.alert("Error with JSON communication! Got response: " + response.getStatusCode() + " "
+ response.getStatusText());
}
}
@Override
public void onError(Request request, Throwable throwable) {
Window.alert("Error: " + throwable.getMessage());
}
});
} catch (RequestException e) {
Window.alert("Error: " + e.getMessage());
}
}
public static final native JsArray<ChatroomMessageJsObject> json2ChatroomMessages(
String json)
/*-{
return eval(json);
}-*/;
public void saveState(String state) {
portletInstance.setState(state);
History.newItem(portletInstance.getId() + STATE_DELIMITER + state);
}
@Override
public void onValueChange(ValueChangeEvent<String> paramValueChangeEvent) {
String token = paramValueChangeEvent.getValue();
if (token == null || token.trim().isEmpty()) {
handleState(STATE_INIT);
} else {
String state = getStateFromToken(paramValueChangeEvent.getValue());
if (state != null) {
handleState(state);
}
}
}
private String getStateFromToken(String token) {
if (token == null)
return null;
int index = token.indexOf(STATE_DELIMITER);
if (index > 0) {
if (token.substring(0, index).equals(portletInstance.getId())) {
return token.substring(index + 1, token.length());
}
}
return null;
}
private void handleState(String state) {
if (state.startsWith(STATE_JOINED_GROUP)) {
int index = state.indexOf(STATE_DELIMITER);
if (index > 0) {
String room = state.substring(index + 1, state.length());
displayChatroomState(room);
}
}
if (state.equals(STATE_INIT)) {
displayInitialState();
}
}
/**
* This class represents a single message in message area
*
* @author Milen Daynkov
*
*/
private static class MessagePanel extends HorizontalPanel {
private static final DateTimeFormat TIME_FORMAT = DateTimeFormat.getFormat("dd-MM-yy HH:mm:ss");
public MessagePanel(ChatroomMessageJsObject message) {
super();
this.addStyleName("message-entry");
VerticalPanel verticalPanel = new VerticalPanel();
verticalPanel.addStyleName("message-entry-author");
verticalPanel.setWidth("150px");
verticalPanel.add(new Label(message.getUser()));
verticalPanel.add(new Label(TIME_FORMAT.format(new Date((long)message.getTime()))));
add(verticalPanel);
Label text = new Label(message.getMessage());
text.setWidth("100%");
text.addStyleName("message-entry-text");
add(text);
}
}
}